/*
 * Copyright 2025 arisgo@163.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.arisgo.cloud.flux.mybatis.service;

import com.arisgo.cloud.flux.mybatis.search.SearchParam;
import com.arisgo.cloud.flux.mybatis.search.page.Pagination;
import com.arisgo.cloud.flux.mybatis.search.page.PageParam;
import com.google.common.collect.Lists;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.util.SqlUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.lang.NonNull;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author Coulson
 * @since 2023-8-9
 */
public interface ICloudService<E, V> {

    V getInstanceVo();

    E getInstanceModel();

    BaseMapper<E> getMapper();

    default Pagination<V> page(@NonNull PageParam pageParam) {
        Page<E> page = getMapper().paginate(pageParam.getPageNo(), pageParam.getPageSize(), pageParam.buildWrapper());
        return new Pagination.Builder<V>()
                .pageNo(pageParam.getPageNo())
                .pageSize(pageParam.getPageSize())
                .totalPages(page.getTotalPage())
                .totalCount(page.getTotalRow())
                .data(convertVo(page.getRecords()))
                .build();
    }

    default V findById(@NonNull Long id) {
        return convertVo(getMapper().selectOneById(id));
    }

    default V findOneByParams(Map<String, Object> params) {
        return convertVo(getMapper().selectOneByMap(params));
    }

    default V findOneByParams(QueryWrapper wrapper) {
        return convertVo(getMapper().selectOneByQuery(wrapper));
    }

    default List<V> findByParams(SearchParam params) {
        return convertVo(getMapper().selectListByQuery(params.buildWrapper()));
    }

    default List<V> findByParams(Map<String, Object> params) {
        return convertVo(getMapper().selectListByMap(params));
    }

    default List<V> findByParams(QueryWrapper wrapper) {
        return convertVo(getMapper().selectListByQuery(wrapper));
    }

    default V saveOrUpdate(@NonNull V vo) {
        E model = convertModel(vo);
        getMapper().insertOrUpdate(model);
        return convertVo(model);
    }

    default boolean delete(@NonNull Long id) {
        return SqlUtil.toBool(getMapper().deleteById(id));
    }

    default boolean delete(@NonNull List<Long> ids) {
        return SqlUtil.toBool(getMapper().deleteBatchByIds(ids));
    }

    default V convertVo(E model) {
        if (Objects.isNull(model)) {
            return null;
        }
        V vo = getInstanceVo();
        BeanUtils.copyProperties(model, vo);
        return vo;
    }

    default List<V> convertVo(List<E> models) {
        if (CollectionUtils.isEmpty(models)) {
            return Lists.newArrayList();
        }
        List<V> vos = Lists.newArrayListWithCapacity(models.size());
        for (E model : models) {
            vos.add(convertVo(model));
        }
        return vos;
    }

    default E convertModel(V vo) {
        if (Objects.isNull(vo)) {
            return null;
        }
        E model = getInstanceModel();
        BeanUtils.copyProperties(vo, model);
        return model;
    }

}